﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Asistente.Model.General;
using Asistente.Model.Representation;

namespace Asistente.Model.COSMIC
{
    public class FunctionalProcess : IMeasurable
    {
        private List<DataMovement> movements;

        private String name;
        public String Name { get { return name; } set { name = value; } }

        public FunctionalProcess(String name)
        {
            this.name = name;
            this.movements = new List<DataMovement>();
        }

        private void addMovement(DataMovement dm)
        {
            if (!isIncluded(dm))
            {
                this.movements.Add(dm);
            }
        }

        public void AddEntryMovement(InterestObject io)
        {
            DataMovement entry = new DataMovement(DataMovementType.Entry, io);
            addMovement(entry);
        }
        public void AddExitMovement(InterestObject io)
        {
            DataMovement exit = new DataMovement(DataMovementType.Exit, io);
            addMovement(exit);
        }
        public void AddReadMovement(InterestObject io)
        {
            DataMovement read = new DataMovement(DataMovementType.Read, io);
            addMovement(read);
        }
        public void AddWriteMovement(InterestObject io)
        {
            DataMovement write = new DataMovement(DataMovementType.Write, io);
            addMovement(write);
        }
       
        public int Measure()
        {
            Int32 size = 0;
            foreach (DataMovement dm in this.movements)
            {
                size = size + dm.Measure();
            }
            return size;
        }

        /// <summary>
        /// Only if the type of the new movement and its interest object are already included in the movement collection
        /// </summary>
        /// <param name="dm"></param>
        /// <returns></returns>
        private Boolean isIncluded(DataMovement dm)
        {
            String[] newMoveTokens = dm.InterestObject.Name.Split('-');//El nombre de las entidades no pueden contener el caracter'-'
            foreach (DataMovement move in this.movements)
            {
                if (move.Type == dm.Type)
                {
                    //Si el movimiento es de tipo entry o Exit entonces esta relacionado con un panel. 
                    //la unica forma de distinguir paneles es por el nombre
                    //ya que al importar un modelo los objetos no se comportan correctamene al metodo .equals()
                    if((move.Type==DataMovementType.Entry)||(move.Type==DataMovementType.Exit)){
                        if (move.InterestObject.Name.Equals(dm.InterestObject.Name))
                        {
                            return true;
                        }
                    }
                     //los movimeintos de lectura y escritura estan asociados a entidades
                    //para verificar se deben comparar entidades contra datagroups
                    //y data groups contra entidades
       
                    if ((move.Type == DataMovementType.Read) || (move.Type == DataMovementType.Write))
                    {
                        String[] tokens = move.InterestObject.Name.Split('-');//los nombres de las entidades no pueden contener el caracter '-'
                        
                        foreach (String tk in tokens)
                        {
                            foreach (String tk2 in newMoveTokens)
                            {
                                if (tk.Trim().Equals(tk2.Trim()))
                                {
                                    return true;
                                }
                            }   
                        }
                    }
                    
                }
            }
            return false;
        }
        public override string ToString()
        {
            String moves = "\t";
            foreach (DataMovement dm in this.movements)
            {
                moves = moves + "\tMove: "+dm.Type.ToString()+ " - Interest Object: " + dm.InterestObject.Name+"\n\t";

            }
            return moves;
        }
        public String ToHtml()
        {
            StringBuilder content = new StringBuilder();
            //content.Append("<tr>");
            content.Append("<td>");
            content.AppendLine(Name);
            content.Append("</td>");
            foreach (DataMovement dm in this.movements)
            {

                //content.Append("<td>");

                content.Append("<tr>");

                content.Append("<td>");
                content.AppendLine(dm.ToString());

                content.Append("</td>");
                content.Append("</tr>");
                //content.Append("</td>");
            }
            //content.Append("</tr>");
            return content.ToString();

        }
        
        //para ordenar los movmientos del proceso funcional (opcional)
        public void Sort(){
            List<DataMovement> entrys = new List<DataMovement>();
            List<DataMovement> exits = new List<DataMovement>();
            List<DataMovement> reads = new List<DataMovement>();
            List<DataMovement> writes = new List<DataMovement>();
            foreach (DataMovement dm in movements)
            {
                if (dm.Type==DataMovementType.Entry)
                {
                    entrys.Add(dm);
                }
                else
                {
                    if (dm.Type == DataMovementType.Exit)
                    {
                        exits.Add(dm);
                    }
                    else {
                        if (dm.Type == DataMovementType.Read)
                        {
                            reads.Add(dm);
                        }
                        else
                        {
                            if (dm.Type == DataMovementType.Write)
                            {
                                writes.Add(dm);
                            }
                        }
                    }
                }
            }
            entrys.AddRange(exits);
            entrys.AddRange(reads);
            entrys.AddRange(writes);
            this.movements = entrys;
        }


        /* optional for debug
        public int getReads() { }
        public int getWrites() { }
        public int getEnties() { }
        public int getExits() { }*/
    }
}
